function [] = ProcessFlights(matchSB)
% Master Flights Data Processing Program
%
% Author: David Goldsmith, Wash. State Dept. of Ecology, dgol461@ecy.wa.gov
% Release date: N/A

  global DB UTCNOW isReleaseVer
  global MatlabCTDProcessing FlightRaw CastRaw % Table aliases
  global ArchiveRoot mSB eN
  global currentCastGUIDs %procLogStr flightLogStr castLogStr 
% Logging paradigm change begun 5/9/2012
% Instead of keeping track of log strings, and thus needing to keep track
% of which strings go with which CastGUIDs, we're just going to keep track
% of the latter and log events to all CastGUIDs in the (dynamic) 
% currentCastGUIDs list.  Thus we note three "levels" of log applicability:
% "Global":  "loggable" events that occur outside the loop over Flights;
%            record of these gets appended to the ProcLogFileBLOB of ALL 
%            CastGUIDs in process
% "Flights": l-able events that occur inside the Flights loop, but outside
%            a Cast loop; these get appended to all of the CURRENT FLIGHT's
%            CastGUIDs
% "Cast":    l-able events that occur inside a Cast loop; record of these 
%            gets appended to the CURRENT CastGUID's ProcLogFileBLOB ONLY.
% The new global variable, currentCastGUIDs, will be updated at each 
% "transition" (i.e., each relevant 'for' loop entry and exit) with the 
% applicable list of CastGUIDs, and this and the log string to append will
% be the only dynamic things required to update the log.  (As far as the
% log file itself is concerned, each new l-able event's log string will 
% simply be appended at the end of the file--no attempt will be made to 
% organize the log file according to the above levels.)

  isReleaseVer = @relVer;

  if nargin, mSB = matchSB; 
  else mSB = 0; end 
  
% Aliases definitions
  MatlabCTDProcessing = 'MatlabCTDProcessing';
  FlightRaw = 'FlightRaw';
  CastRaw = 'CastRaw';
  ArchiveRoot = 'Y:\Seabird\EAPMW\FlightsArchive';
  UTCNOW = utcnow();

  [logStr, proceed] = setupProcess(['Process datetime (UTC): '...
                                        datestr(UTCNOW) '.  ']);
  if proceed
    % Get the stuff listed below for unprocessed flights
    % ALERT: modifying the cols and/or their order in the following query 
    % constructor will require indexing changes in subsequent code up to
    % the line: "result = pkQ.structFromResult;"
      pkQ = query(DB, struct('tbls', {{MatlabCTDProcessing}},...
                             'cols', {{'FlightDBName', 'FlightGUID',...
                                       'FlightDatetime', 'CastGUID',...
                                       'CastNumber', 'DailyPressOffset',...
                                       'SiteID', 'SiteCode', 'SiteVisitGUID',...
                                       'Lat', 'TimeDown', 'HEXFileName',...
                                       'CTDHexFileBLOB', 'CONFileName',...
                                       'CONFileBLOB', 'ScanNumBegin',...
                                       'ScanNumEnd'}},...
                             'where', {{'(FlightProcessed = 0)'}}));
      if ~isempty(pkQ.errCode)
          logStr = [logStr [pkQ.errCode{:}] '.  '];
      else
          pkQ.submitStatement
          if ~isempty(pkQ.errCode)
              logStr = [logStr [pkQ.errCode{:}] '.  '];
          else
            % Clear any extant logStr's
              currentCastGUIDs = pkQ.result(:,4);
              saveLog({}) % Passing saveLog an empty clears all current GUID logs
              saveLog(logStr); logStr = ''; % Now save current logStr and reset 
            % Remove & report records with "fatal" missing data, i.e.,
            % CTDHexFileBLOB and/or CONFileBLOB
              missing = strcmp(pkQ.result(:,13), 'null') | ... % col 13 = CTDHexFileBLOBs
                        strcmp(pkQ.result(:,15), 'null'); % col 15 = CONFileBLOBs
              if all(missing)
                  logStr = [logStr 'All unprocessed flights are missing their '...
                            'CTDHexFileBLOB and/or their CONFileBLOB: each '...
                            'FlightDatetime must have both BLOBs in the DB to '...
                            'be processed; please manually check and correct '...
                            'the DB before attempting to reprocess, aborting.  '];
                  saveLog(logStr);
%                  eN.send = 1;
              else
                  if any(missing)
                      incompRecs = pkQ.result(missing, 4); % col 4 = CastGUIDs
                      if numel(incompRecs)==1
                          logStr = [logStr 'CastGUID ' incompRecs{1} ' appears '...
                                    'to be missing its CTDHexFileBLOB and/or '...
                                    'CONFileBLOB '];
                      else
                          logStr = [logStr 'CastGUIDs ' incompRecs{1} ...
                                    cellfun(@(x) sprintf(', %s', x),...
                                    incompRecs(2:end), 'UniformOutput', 0)'...
                                    ' appear to be missing their CTDHexFileBLOBs'...
                                    ' and/or CONFileBLOBs '];
                          logStr = [logStr{:}];
                      end
                      logStr = [logStr 'from the DB, both of which are necessary '...
                                'for processing.  Continuing with processing '...
                                'the remaining cast(s).  '];                            
                      pkQ.result = pkQ.result(~missing,:);
                    % Update currentCastGUIDs in light of "missing"
                      currentCastGUIDs = pkQ.result(:,4);
                      saveLog(logStr); logStr = '';
                  end
                % Make folder(s) by date for archives, if they don't already exist
                  dts = pkQ.result(:,3); % col 3 = FlightDatetimes
                  paths = date2folder(ArchiveRoot, dts);
                  failed = find(~cellfun(@isempty, regexp(paths, 'error')));
                % Note: failing to have a directory is not a fatal error, 
                % even it all failed, because, at least up to this point, 
                % nothing has happened that would prevent us from pushing 
                % results to the DB
                  if ~isReleaseVer() && isempty(failed)
                      paths{1} = '_dev version testing';
                      paths{end} = '_dev version testing';
                      failed = [1 numel(dts)];
                  end
                  if ~isempty(failed) 
                      for f = failed
                          logStr = [logStr 'Archive path for CastGUID ' ...
                                    pkQ.result{f,4} ' didn''t exist and '...
                                    'couldn''t be made (date2folder retruned '...
                                    'error: ' paths{f} '); its results may '...
                                    'be available only in the DB.  '];
                      end
                      saveLog(logStr); logStr = '';
                  end
                  paths(failed) = deal(constCellStrArr('', size(failed)));
                  result = pkQ.structFromResult;
                  result.paths = paths;
                  DB.recordsInProcess = struct('col', {{'CastGUID'}, {'FlightGUID'}},...
                                               'val', {result.CastGUID, result.FlightGUID});

                % Process flights
                  results = doProcess(result);
                  
                % Prepare for shutdown
                  if ischar(results)
                      logStr = results;
                      eN.send = 1;
                  end
                  if ~isdeployed
                      eN.mail_recip = {'dgol461@ecy.wa.gov', 'bsac461@ecy.wa.gov'};
                  end
                  if isdeployed && eN.send==0 ...
                     && (UTCNOW < datenum('2012-07-07'))
                      eN.send = 1;
                  end
                  
              end
          end
      end
  end
  
  shutdownProcess(logStr)

end

function swtch = relVer()
    swtch = isempty(regexp(mfilename, '_dev', 'ONCE'));
end